package com.superbytecode.cloud.redis.client;

import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * All rights Reserved, Designed By www.super-master.com
 *
 * @ProjectName: sanskrit
 * @Package: com.superbytecode.cloud.redis.client
 * @ClassName: RedisTemplateClient
 * @Description: [Redis工具类]
 * <p> </p>
 * @Author: [Lance Ting]
 * @Date: 2024/8/19 11:43
 * @Version: V1.0
 * @Copyright: 2024 www.super-master.cn Inc. All rights reserved.
 * TODO: 注意,本文件Lance Ting所作,如果转载或使用请标明具体出处!
 **/
@SuppressWarnings("all")
public class RedisTemplateClient {
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    @Resource
    private RedissonClient redissonClient;

    // ------------------------------------ Common ------------------------------------

    /**
     * 指定缓存失效时间
     * <p> 命令EXPIRE </p>
     *
     * @param key     键
     * @param seconds 时间（秒）
     * @return true / false
     */
    public boolean expire(String key, long seconds) {
        return expire(key, seconds, TimeUnit.SECONDS);
    }

    /**
     * 指定缓存失效时间
     * <p> 命令EXPIRE </p>
     *
     * @param key      键
     * @param time     时间（秒）
     * @param timeUnit 时间单位
     * @return true / false
     */
    public boolean expire(String key, long time, TimeUnit timeUnit) {
        if (time > 0) {
            return Objects.equals(redisTemplate.expire(key, time, timeUnit), Boolean.TRUE);
        }
        return false;
    }

    /**
     * 根据 key 获取过期时间
     * <p>TTL命令</p>
     *
     * @param key 键
     * @return 秒
     */
    public long ttl(String key) {
        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
    }

    /**
     * 判断 key 是否存在
     * <p>
     * 命令EXISTS
     * </p>
     *
     * @param key 键
     * @return true / false
     */
    public boolean exists(String key) {
        return redisTemplate.hasKey(key);
    }

    /**
     * 查询所有满足表达式的key
     * <p>
     * 命令KEYS，实际是利用SCAN命令实现，不会产生阻塞
     * </p>
     *
     * @param pattern 表达式
     * @return 符合表达式的key的集合
     * @complexity O(n)
     */
    public Set<String> scan(String pattern) {
        if (StringUtils.isBlank(pattern)) {
            throw new IllegalArgumentException("参数不正确");
        }
        return redisTemplate.execute((RedisCallback<Set<String>>) connection -> {
            Set<String> keys = new HashSet<>();
            Cursor<byte[]> cursor = connection.scan(ScanOptions.scanOptions().match(pattern).count(1000).build());
            while (cursor.hasNext()) {
                keys.add(new String(cursor.next()));
            }
            return keys;
        });
    }

    // ------------------------------------ string ------------------------------------

    /**
     * 放入缓存
     * (命令 SET)
     *
     * @param key   键
     * @param value 值
     */
    public void set(String key, Object value) {
        redisTemplate.opsForValue().set(key, value);
    }

    /**
     * 放入缓存
     * (命令 SET)
     *
     * @param key   键
     * @param value 值
     */
    public void set(String key, Object value, long timeout) {
        set(key, value, timeout, TimeUnit.SECONDS);
    }

    /**
     * 放入缓存
     * (命令 SET)
     *
     * @param key   键
     * @param value 值
     */
    public void set(String key, Object value, long timeout, TimeUnit timeUnit) {
        redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
    }
    //

    /**
     * 获取缓存（string数据结构） 通过泛型T指定缓存数据类型
     * (命令 GET)
     *
     * @param key 键
     * @return 值
     * // @see #hGetAll
     */
    @SuppressWarnings("unchecked")
    public <T> T get(String key) {
        return key == null ? null : (T) redisTemplate.opsForValue().get(key);
    }


    // ------------------------------------ hash（map） ------------------------------------
    // ------------------------------------ set ------------------------------------
    // ------------------------------------ zset ------------------------------------

    /**
     * 获取指定位置元素
     *
     * @param key   key
     * @param index 索引
     * @param <T>   限制类型
     * @return 查询结果
     */
    @SuppressWarnings("unchecked")
    public <T> T zGet(String key, int index) {
        Set<Object> objects = redisTemplate.opsForZSet().range(key, index, index + 1);
        if (CollectionUtils.isEmpty(objects)) {
            return null;
        }
        return (T) objects.iterator().next();
    }
    // ------------------------------------ list ------------------------------------
    // ------------------------------------ bitmap ------------------------------------

    // ------------------------------------ lock ------------------------------------

    /**
     * 获取Redis分布式锁
     *
     * @param key 锁的key
     * @return RedisLock
     */
    public RLock getLock(String key) {
        return redissonClient.getLock(key);
    }
    // ------------------------------------ pipelined ------------------------------------
    // ------------------------------------ hyperLogLogAdd ------------------------------------

}